/**
 * Copyright (c) 2008 Luciano Bustos - riaevolution.com, All Rights Reserved.
 * 
 * Contact luchyx@riaevolution.com
 * See www.riaevolution.com
 *  
 * Permission is hereby granted, free of charge, to any person obtaining a copy of 
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all 
 * copies or substantial portions of the Software.
 * 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 * */
package com.riaevolution.components
{
	/**
	 * Combobox extended.
	 * Usefull when you need to select an Index depending the data value or other diferent than the
	 * the index in the dataprovider.
	 * It's like an search & select.
	 * You pass a value to search. in the dataField properties of the n-elements in the dataprovider.
	 * Also you can change the dataFiel property with my_combo_plus.dataField = "price" property. 
	 * 
	 * Example Usage:
	 * you got products_items = [
	 * 		{price:15,label:"Rubber duck"},
	 *		{price:2,label:"Mayard duck"},
	 * 		{price:80,label:"real duck"}
	 * ]
	 * my_combo_plus.dataProvider = products_items;
	 * my_combo_plus.displayItemToolTip = true; //turn on the tooltips item rollover
	 * my_combo_plus.defaultItemToolTipText = "No description avaialble";
	 * my_combo_plus.defaultItemToolTipField = 'description';
	 * my_combo_plus.dataField = "price";		// asign the field in wich we want to seach
	 * my_combo_plus.selectedIndexData = 15;	//will select "Rubber duck"
	 * my_combo_plus.selectedIndex = 0;			//will select "Rubber duck"
	 * 
	 **/
	
	import flash.events.Event;
	import flash.geom.Point;
	
	import mx.collections.ICollectionView;
	import mx.controls.ComboBox;
	import mx.core.IToolTip;
	import mx.events.DropdownEvent;
	import mx.events.ListEvent;
	import mx.managers.ToolTipManager;
	
	
	public class ComboBoxPlus extends ComboBox
	{
		/**
		 * data field is the property name in with we search
		 * trhow the dataprovider of the combobox, by default is "data";
		 * 
		 **/
		
		private var _data_field:String = "data";
		private var _selIndex:int;
		private var maped_obj:Object;
		private var cust_tip:IToolTip;
		private var _selectedValue:Object;
		
		
		[Bindable]
		public var displayItemToolTip:Boolean = false;
		public var defaultItemToolTipText:String = "";
		public var defaultItemToolTipField:String;
		
		private var _syncSelectedIndex:Boolean = false;
		//constructor
		public function ComboBoxPlus()
		{
			super();
			this.addEventListener(mx.events.ListEvent.ITEM_ROLL_OVER,onItemRollOver);
			this.addEventListener(mx.events.DropdownEvent.CLOSE,removeTip);
		}
		
		public function rollOverTipText(idx:Number):String {
			var msj:String;
			var dp:Object = this.dataProvider;
			try{
				if(defaultItemToolTipField == null){
					msj = dp[idx][dataField];
				}
				else {
					msj = dp[idx][defaultItemToolTipField];
				}	
			}
			catch(e:Error){
				msj = defaultItemToolTipText;
			}
			return msj;
		}
		
		public function ItemToolTipText():String {
			var msj:String;
			var dp:Object = this.dataProvider;
			
			if(defaultItemToolTipField == null){
				msj = dp[this.selectedIndex][dataField];
			}
			else {
				msj = dp[this.selectedIndex][defaultItemToolTipField];
			}
			return msj;
		}
		
		public function removeTip(e:DropdownEvent=null):void {
			if(cust_tip != null && displayItemToolTip) {
				ToolTipManager.destroyToolTip(cust_tip);
				cust_tip = null;
			}
		}
		
		private function onItemRollOver(event:ListEvent):void {
			if(!displayItemToolTip) return;
			if(cust_tip == null){
				cust_tip = ToolTipManager.createToolTip("",mouseX,mouseY,null,this);
			}
			if(rollOverTipText(event.rowIndex).length <1){
				cust_tip.visible = false;
				return;
			}
			else {
				cust_tip.visible = true;
			}
			
			var pot:Point = new Point(mouseX+20,mouseY+20);
			pot = localToGlobal(pot);
			cust_tip.text = rollOverTipText(event.rowIndex);
			/*
			 * Fix the position if the component size and his x,y coord is bigger than the stage. 
			 */
			if(cust_tip.measuredHeight+pot.y > stage.stageHeight) {
				pot.y = stage.stageHeight - cust_tip.measuredHeight - 20; 
			}
			if(cust_tip.measuredWidth+pot.x > stage.stageWidth) {
				pot.x =  stage.stageWidth - cust_tip.measuredWidth - 20; 
			}
			cust_tip.move(pot.x,pot.y);
		}
		
		
		private var _privateUpdate:Boolean = false;
		private var _dpChange:Boolean = false;
		private var _internalUpdateIndex:Boolean = false;
		private var _selectedIndexDataChange:Boolean = false;
		
		//setter and getters
		private var _dataFieldChange:Boolean = false;
		[Bindable]		
		public function set dataField(s:String):void {
			//trace('dataFieldChange');
			_data_field = s;
			_dataFieldChange = true;
			invalidateProperties();
			invalidateDisplayList();
		}
		public function get dataField():String {
			return _data_field;
		}
		
		override protected function commitProperties():void {
			super.commitProperties();
			/*if(_dpChange) {
				trace("DataProvider Changed");
				_dpChange = false;
				resyncMappedObject();
			}
			
			*/
			if(_dataFieldChange) {
				onDataProviderChange();
				_dataFieldChange = false;
			}
			
			if(_syncSelectedIndex) {
				_selIndex = selectedIndex;
				_privateUpdate = true;
				selectedIndexData = getIndexData();
				_privateUpdate = _syncSelectedIndex = false;
			}
		}
		/**
		 * Override the dataProvider setter
		 * 
		 **/
		override public function set dataProvider(value:Object):void {
			super.dataProvider = value;
			_dpChange = true;
		}
		
		
		override public function set selectedIndex(value:int):void {
			//si lo update internamente no llamo updateIndeData
			super.selectedIndex = value;
			_syncSelectedIndex = true;
			invalidateProperties();
			invalidateDisplayList();
		}
		
		/**
		 * Obtiene y/o Settea el valor del indice seleccionado  
		 * 
		 **/
		[Bindable]
    	    			
		public function get selectedIndexData():* {			
			return _selectedValue;
		}
		public function set selectedIndexData(value:Object):void{
			
			//trace('selectedIndexData: ' + value );
			
			_selectedValue = value;
			
			/*
			if( _privateUpdate) return;
			
			if( !_selectedValue || maped_obj[_selectedValue] == undefined) {
				
				_selIndex = -1;
				
			} else {
				_selIndex = maped_obj[_selectedValue];
			}
			_selectedIndexDataChange = true;
			
			invalidateProperties();
			invalidateDisplayList();
			*/
			
			if( _selectedValue) {
				onDataProviderChange();
			} else {
				selectedIndex = -1;
			}
			invalidateProperties();
			invalidateDisplayList();
		}
		
		private function onDataProviderChange(event:Event = null):void {
			
			if(!this.dataField) return;
			try {
				var length_int:int = this.dataProvider.length;
				var dd:int = -1;
				while (length_int--) {
					var item:Object;
					if(dataField == "" || !dataField) {
						item = dataProvider[length_int];
					} else {
						item = dataProvider[length_int][this.dataField];
					}
					if(item == _selectedValue) {
						dd = length_int;
						break;
					}
				};
			}
			catch(e:Error) {
				//do nothing
			}
			this.selectedIndex = dd;
		}
		
		/**
		 * Devuelve el indice del objeto seleccionado.
		 * 
		 **/
		private function getIndexData():*{
			
			if(_selIndex == -1 || !this.dataProvider) return null;
			try {
				var dp:ICollectionView  = this.dataProvider as ICollectionView;
				if( dp == null || dp.length < 1 ||  dp[_selIndex] == null || dp[_selIndex][_data_field] == null ) return null;
				
				return dp[_selIndex][_data_field];
			}
			catch(e:Error) {
				return _selectedValue;
			}
		}
		/**
		 * Metodo interno para buscar y mapear los objectos segun el indice. 
		 **/
		protected function resyncMappedObject():void{
			
			maped_obj = new Object();
			var dp:Object = this.dataProvider;
			if(!dp) return;
			var length_int:int = dp.length;
			while (length_int--)
			{
				try {
					maped_obj[dp[length_int][dataField]] = length_int;
				}
				catch (e:Error) {
					//
					trace(e);
				}
			};
		}
	}
}